package com.shiroexploit.gui;

import com.shiroexploit.task.TestConnectionTask;
import com.shiroexploit.util.Config;
import com.shiroexploit.util.HttpRequestInfo;
import com.shiroexploit.util.PayloadType;
import com.shiroexploit.util.Tools;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

public class StartPane extends Application {

    private Config config = Config.getInstance();
    private BorderPane borderPane = new BorderPane();
    private BorderPane simpleRequestSubpane = new BorderPane();
    private BorderPane complexRequestSubpane = new BorderPane();
    private ComboBox<String> comboBox = new ComboBox<>();
    private ComboBox<String> platformCombox = new ComboBox<>();
    private CheckBox complexHttpRequest = new CheckBox("复杂Http请求");
    private TextField urlTextField = new TextField();
    private TextArea cookieField = new TextArea();
    private TextArea requestBodyField = new TextArea();
    private Button next = new Button("下一步");
    private CheckBox useHttps = new CheckBox("使用Https");
    private Label labelForPlatform;
    private CheckBox specifyKeyAndGadget = new CheckBox("指定Key和Gadget");
    private ComboBox<String> keyComboBox = new ComboBox<>();
    private ComboBox<String> gadgetComboBox = new ComboBox<>();


    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {

        Pane borderPane = new StartPane().getPane();
        primaryStage.setTitle("Shiro550/721漏洞检测  by飞鸿");
        primaryStage.setScene(new Scene(borderPane, 800, 550));
        primaryStage.show();


//        //测试
//        MainPane pane = new MainPane();
//        primaryStage.setTitle("Shiro550/721漏洞检测  by飞鸿");
//        primaryStage.setScene(new Scene(pane.getPane(), 800,600));
//        primaryStage.show();
    }

    public StartPane(){
        drawPane();
        addListeners();
    }

    public Pane getPane() {
        return borderPane;
    }

    private void drawPane(){
        borderPane.setPadding(new Insets(10,10,10,10));

        Label label = new Label("选择要验证的漏洞");
        List<String> data = new ArrayList<>();
        data.add("Shiro550");
        data.add("Shiro721");
        comboBox.setItems(FXCollections.observableArrayList(data));
        comboBox.setPrefHeight(35);
        comboBox.setPrefWidth(150);
        comboBox.getSelectionModel().select(0);

        labelForPlatform = new Label("目标操作系统");
        List<String> data2 = new ArrayList<>();
        data2.add("Linux");
        data2.add("Windows");
        platformCombox.setItems(FXCollections.observableArrayList(data2));
        platformCombox.setPrefHeight(35);
        platformCombox.setPrefWidth(150);
        platformCombox.getSelectionModel().select(0);
        labelForPlatform.setDisable(true);
        platformCombox.setDisable(true);


        GridPane gridPane = new GridPane();
        gridPane.setAlignment(Pos.CENTER);
        gridPane.setPadding(new Insets(10,20,10,20));
        gridPane.add(label, 0,0);
        gridPane.add(comboBox,1,0);
        gridPane.add(labelForPlatform,2,0);
        gridPane.add(platformCombox, 3, 0);
        gridPane.add(complexHttpRequest,4,0);
        gridPane.setHgap(25);

        keyComboBox.setItems(FXCollections.observableArrayList(config.getKeys()));
        keyComboBox.setPromptText("指定Key");
        keyComboBox.setDisable(true);
        gadgetComboBox.setItems(FXCollections.observableArrayList(Tools.getPayloadNames()));
        gadgetComboBox.setPromptText("指定Gadget");
        gadgetComboBox.setDisable(true);
        GridPane gridPane2 = new GridPane();
        gridPane2.setAlignment(Pos.CENTER);
        gridPane2.setHgap(10);
        gridPane2.setPadding(new Insets(10,0,10,0));
        gridPane2.add(specifyKeyAndGadget, 0, 1);
        gridPane2.add(keyComboBox, 1, 1);
        gridPane2.setColumnSpan(gadgetComboBox, 2);
        gridPane2.add(gadgetComboBox, 3,1);

        VBox vBox = new VBox();
        vBox.getChildren().addAll(gridPane, gridPane2);

        urlTextField.setPrefHeight(35);
        urlTextField.setPromptText("目标地址");
        cookieField.setPrefHeight(300);
        cookieField.setWrapText(true);
        cookieField.setPromptText("rememberMe=dGhpcyBpcyBhIGRlbW9uc3RyYXRpb24gc3RyaW5nCg==");
        cookieField.setDisable(true);
        simpleRequestSubpane.setPadding(new Insets(10,10,10,10));
        simpleRequestSubpane.setTop(urlTextField);
        simpleRequestSubpane.setMargin(urlTextField, new Insets(0,0,20,0));
        simpleRequestSubpane.setCenter(cookieField);

        requestBodyField.setPrefHeight(350);
        requestBodyField.setWrapText(true);
        requestBodyField.setPromptText("POST /someurl HTTP/1.1\r\n" +
                "Host: passport.zhaopin.com\r\n" +
                "Connection: close\r\n" +
                "Accept: application/json, text/javascript, */*; q=0.01\r\n" +
                "Accept-Encoding: gzip, deflate\r\n" +
                "Accept-Language: zh-CN,zh;q=0.9\r\n" +
                "Cookie: x-zp-client-id=bea678e6-7fa8-4cfd-8d23-5d98f8876702; rememberMe=dGhpcyBpcyBhIGRlbW9uc3RyYXRpb24gc3RyaW5nCg==\r\n\r\n" +
                "param1=value1&param2=value2\r\n\r\n");
        complexRequestSubpane.setPadding(new Insets(10,10,10,10));
        complexRequestSubpane.setTop(useHttps);
        complexRequestSubpane.setMargin(useHttps, new Insets(0,0,10,0));
        complexRequestSubpane.setCenter(requestBodyField);

        borderPane.setTop(vBox);
        borderPane.setCenter(simpleRequestSubpane);

        HBox hbox = new HBox();
        hbox.getChildren().add(this.next);
        hbox.setAlignment(Pos.CENTER);
        borderPane.setBottom(hbox);
        borderPane.setMargin(hbox, new Insets(10,0,10,0));
    }


    public void update(){
        int vul = Config.getInstance().getVulType();
        comboBox.getSelectionModel().select(vul);

        HttpRequestInfo requestInfo  = Config.getInstance().getRequestInfo();
        if(requestInfo.getHeaders().size() == 0){
            complexHttpRequest.setSelected(false);
            urlTextField.setText(requestInfo.getRequestURL());
            if(requestInfo.getRememberMeCookie() != null){
                cookieField.setText(requestInfo.getRememberMeCookie());
            }
        }else{
            complexHttpRequest.setSelected(true);
            requestBodyField.setText(requestInfo.getOriginal());
        }

        int platform = Config.getInstance().getPlatform();
        platformCombox.getSelectionModel().select(platform);
    }

    private void addListeners(){
        comboBox.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<String>() {
            @Override
            public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
                if(newValue.equalsIgnoreCase("shiro721")){
                    cookieField.setDisable(false);
                    labelForPlatform.setDisable(false);
                    platformCombox.setDisable(false);
                }

                if(newValue.equalsIgnoreCase("shiro550")){
                    cookieField.setDisable(true);
                    labelForPlatform.setDisable(true);
                    platformCombox.setDisable(true);
                }
            }
        });


        complexHttpRequest.selectedProperty().addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
               if(newValue == true){
                   borderPane.setCenter(complexRequestSubpane);
               }else{
                   borderPane.setCenter(simpleRequestSubpane);
               }
            }
        });

        specifyKeyAndGadget.selectedProperty().addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                if(newValue == true){
                    keyComboBox.setDisable(false);
                    gadgetComboBox.setDisable(false);
                }else{
                    keyComboBox.setDisable(true);
                    gadgetComboBox.setDisable(true);
                }
            }
        });


        next.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                if(specifyKeyAndGadget.isSelected()){
                    if(keyComboBox.getSelectionModel().getSelectedIndex() == -1){
                        PromptMessageUI.getAlert("输入错误", "您尚未指定 Key");
                        return;
                    }else{
                        List<String> keys = new ArrayList<>();
                        String key = keyComboBox.getSelectionModel().getSelectedItem().trim();
                        keys.add(key);
                        config.setKeys(keys);
                    }

                    if(gadgetComboBox.getSelectionModel().getSelectedIndex() == -1){
                        PromptMessageUI.getAlert("输入错误", "您尚未指定 Gadget");
                        return;
                    }else{
                        List<PayloadType> gadgets = new ArrayList<>();
                        String name = gadgetComboBox.getSelectionModel().getSelectedItem().trim();
                        gadgets.add(Tools.getPayloadByName(name));
                        config.setGadgets(gadgets);
                    }
                }


                config.setVulType(comboBox.getSelectionModel().getSelectedIndex());
                config.setPlatform(platformCombox.getSelectionModel().getSelectedIndex());

                Stage currentStage = (Stage)borderPane.getScene().getWindow();
                if(!complexHttpRequest.isSelected()){
                    String url = urlTextField.getText();
                    url = url != null ? url.trim() : null;
                    String cookie = cookieField.getText();
                    cookie = cookie != null ? cookie.trim() : null;

                    boolean bool = validateURL(url);
                    if(comboBox.getSelectionModel().getSelectedIndex() == 1){
                        bool = bool && validateCookie(url, cookie);
                    }

                    if(bool) {
                        HttpRequestInfo httpRequestInfo = new HttpRequestInfo();
                        httpRequestInfo.setRequestMethod("GET");
                        httpRequestInfo.setRequestURL(url);
                        if(config.getVulType() == 1)
                            httpRequestInfo.setRememberMeCookie(Hex.encodeHexString(Base64.decodeBase64(cookie.split("=",2)[1])));
                        config.setRequestInfo(httpRequestInfo);

                        TestConnectionTask task = new TestConnectionTask(httpRequestInfo);
                        task.valueProperty().addListener(new ChangeListener<Integer>() {
                            @Override
                            public void changed(ObservableValue<? extends Integer> observable, Integer oldValue, Integer newValue) {
                                if(task.getStatus() == 1){
                                    nextStage();
                                }

                                if(task.getStatus() == -1){
                                    PromptMessageUI.getAlert("目标地址无法访问","您输入的 URL 无法正常访问");
                                }
                            }
                        });

                        PenddingUI penddingUI = new PenddingUI(task, currentStage);
                        penddingUI.activateProgressBar();
                    }
                }else{
                    String requestBody = requestBodyField.getText();
                    HttpRequestInfo httpRequestInfo = new HttpRequestInfo();

                    if(requestBody == null || requestBody.trim().equals("")){
                        PromptMessageUI.getAlert("HTTP请求不能为空","请输入一个有效的HTTP请求");
                        return;
                    }

                    try{
                        httpRequestInfo.parse(requestBody, useHttps.isSelected());
                    }catch (Exception e){
                        PromptMessageUI.getAlert("HTTP请求格式不正确","请输入一个格式正确的HTTP请求");
                        return;
                    }

                    if(comboBox.getSelectionModel().getSelectedIndex() == 1){
                        if(httpRequestInfo.getRememberMeCookie() == null){
                            PromptMessageUI.getAlert("缺失有效的rememberMe Cookie","未提供rememberMe Cookie或者提供的remeberMe Cookie格式不正确");
                            return;
                        }
                    }

                    config.setRequestInfo(httpRequestInfo);

                    TestConnectionTask task = new TestConnectionTask(httpRequestInfo);
                    task.valueProperty().addListener(new ChangeListener<Integer>() {
                        @Override
                        public void changed(ObservableValue<? extends Integer> observable, Integer oldValue, Integer newValue) {
                            if(task.getStatus() == 1){
                                nextStage();
                            }

                            if(task.getStatus() == -1){
                                PromptMessageUI.getAlert("目标地址无法访问","您输入的 Http 请求解析后无法正常访问");
                            }
                        }
                    });

                    PenddingUI penddingUI = new PenddingUI(task, currentStage);
                    penddingUI.activateProgressBar();

                }
            }
        });
    }

    private void nextStage() {
        Stage newStage = new Stage();
        ConfigPane configPane = new ConfigPane(StartPane.this);
        Pane next = configPane.getPane();
        configPane.update();
        newStage.setTitle(Config.getInstance().getRequestInfo().getRequestURL());
        newStage.setScene(new Scene(next, 550, 500));
        Stage currentStage = (Stage) borderPane.getScene().getWindow();
        currentStage.hide();
        newStage.show();
    }

    private boolean validateURL(String url){
        if(url == null || url.trim().equals("")){
            PromptMessageUI.getAlert("URL不能为空","请输入一个有效的URL");
            return false;
        }

        if(!url.startsWith("http://") && !url.startsWith("https://")){
            PromptMessageUI.getAlert("URL格式不正确","请输入完整的URL，包括http(s)前缀");
            return false;
        }

        try{
            URL u = new URL(url);
        } catch (MalformedURLException e) {
            PromptMessageUI.getAlert("URL格式不正确","请输入正确格式的URL");
            return false;
        }

        return true;
    }


    private boolean validateCookie(String url, String cookie){
        if(cookie == null || cookie.trim().equals("")){
            PromptMessageUI.getAlert("Cookie不能为空","请输入一个有效的rememberMe Cookie");
            return false;
        }

        if(!cookie.startsWith("rememberMe=")){
            PromptMessageUI.getAlert("cookie格式不正确","请输入正确格式的rememberMe cookie");
            return false;
        }

//        String rememberMe = cookie.split("=",2)[1];
//        if(HttpRequest.request(url, rememberMe)){
//            return true;
//        }else{
//            PromptMessageUI.getAlert("无效cookie","您输入的cookie无法正常使用");
//        }

        return true;
    }
}